/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "UISystem.h"

#include "OgreRenderWindow.h"
#include "CEGUIOgreRenderer.h"
#include "CEGUIOgreResourceProvider.h"
#include "CEGUIOgreImageCodec.h"

#include "InputSystem.h"
#include "SystemUtil.h"
#include "ClientConfig.h"
#include "ClientUtil.h"
#include "IMECHS.h"

#include "GameScene.h"

#include "LoginUIScreen.h"

//The ui implement use CEGUI,and depend on OGRE
namespace PQClient
{
	std::string UISystem::GroupName_ImageSet="imagesets";
	std::string UISystem::GroupName_Font="fonts";
	std::string UISystem::GroupName_Scheme="schemes";
	std::string UISystem::GroupName_Layout="layouts";
	std::string UISystem::GroupName_LookFeel="looknfeels";

	
	UISystem::UISystem() : _window(0)
	{
	}

	UISystem::~UISystem()
	{
	}


	void UISystem::init()
	{

		if (CEGUI::System::getSingletonPtr()){
			assert("CEGUI::System object is already initialised.");
		}

		//Note: CEGUI render ui on ogre render window,nothing related with ogre scene manager.
		//So there can be multiple scene,but only one gui system.
		_window=(Ogre::RenderWindow*)Ogre::Root::getSingleton().getRenderTarget(CLINET_RENDER_WINDOW_NAME);
		assert(_window);
		
		CEGUI::OgreRenderer& renderer=CEGUI::OgreRenderer::create(*_window);
		CEGUI::System::create(renderer);


		configCEGUI();

		CEGUI::MouseCursor::getSingleton().setImage(CEGUI::System::getSingleton().getDefaultMouseCursor());

		//SystemUtil
		showMouseCursor(false);
		CEGUI::MouseCursor::getSingleton().show();


		InputSystem::getSingleton().addKeyListener(this,"GUI_KEY_LISTENER");
		InputSystem::getSingleton().addMouseListener(this,"GUI_MOUSE_LISTENER");

		initScreens();

	}

	void UISystem::configCEGUI()
	{
		//define cegui resources

		CEGUI::DefaultResourceProvider * rp=static_cast<CEGUI::DefaultResourceProvider*>(CEGUI::System::getSingleton().getResourceProvider());
		rp->setResourceGroupDirectory(GroupName_Scheme,CLIENT_UI_SCHEME_PATH);
		rp->setResourceGroupDirectory(GroupName_ImageSet,CLIENT_UI_IMAGESET_PATH);
		rp->setResourceGroupDirectory(GroupName_Font, CLIENT_UI_FONT_PATH);
		rp->setResourceGroupDirectory(GroupName_Layout, CLIENT_UI_LAYOUT_PATH);
		rp->setResourceGroupDirectory(GroupName_LookFeel, CLIENT_UI_LOOKFELL_PATH);

		CEGUI::Scheme::setDefaultResourceGroup(GroupName_Scheme);
		CEGUI::Imageset::setDefaultResourceGroup(GroupName_ImageSet);
		CEGUI::Font::setDefaultResourceGroup(GroupName_Font);
		CEGUI::WidgetLookManager::setDefaultResourceGroup(GroupName_LookFeel);
		CEGUI::WindowManager::setDefaultResourceGroup(GroupName_Layout);
		
        //CEGUI::System::getSingleton().setDefaultTooltip("TaharezLook/Tooltip");


		//add schemes
		CEGUI::SchemeManager::getSingleton().create(CLIENT_UI_SCHEME_MAIN);

		//set default font
		CEGUI::System::getSingleton().setDefaultFont(CLINET_DEFAULT_FONT_NAME);
		//set mouser cursor to normal
        CEGUI::System::getSingleton().setDefaultMouseCursor("MouseCur", "putong");

        CEGUI::MouseCursor::getSingleton().setImage(CEGUI::System::getSingleton().getDefaultMouseCursor());

        //SystemUtil
        showMouseCursor(false);
        CEGUI::MouseCursor::getSingleton().show();

		
	}

	void UISystem::update(float deltaT)
	{
		int width=_window->getWidth();
		int height=_window->getHeight();


		CEGUI::Size size(width,height);
		CEGUI::System::getSingleton().getRenderer()->setDisplaySize(size);

		//may do ui animations

	}

	uint UISystem::getWindowWidth()
	{
		return _window->getWidth();
	}

	uint UISystem::getWindowHeight()
	{
		return _window->getHeight();
	}

	void UISystem::initScreens()
	{
		for(int i=0;i<UIScreen::UIScreen_Count;++i){
			_screens[i]=0;//new LoginUIScreen();
		}

		_screens[UIScreen::UIScreen_Login]=new LoginUIScreen();

		//set login screen as startup screen
		setCurrentScreen(UIScreen::UIScreen_Login);
	}

	void UISystem::setCurrentScreen(UIScreen::Type type)
	{
		_activeScreen=_screens[type];

		CEGUI::System* sys=CEGUI::System::getSingletonPtr();
		if(!sys){
			return;
		}
		
		if(_activeScreen){	
				CEGUI::Window *win=_activeScreen->getRootWindow();
				sys->setGUISheet(win);
				CEGUI::System::getSingleton().signalRedraw();
		}else{
				sys->setGUISheet(0);
				CEGUI::System::getSingleton().signalRedraw();
				
		}

	}
	

	bool UISystem::mouseMoved( const OIS::MouseEvent &e )
	{
		//update cegui
		//out viewport
		CEGUI::System* sys=CEGUI::System::getSingletonPtr();
		if(!sys){
			return true;
		}

		int cnt=_window->getNumViewports();
		if(cnt==0){
			return true;
		}

		int x=e.state.X.abs;
		int y=e.state.Y.abs;
		if(x<_window->getViewport(0)->getActualLeft()+2||(y<_window->getViewport(0)->getActualTop()+0.5)
			||(x>(_window->getViewport(0)->getActualLeft()+_window->getViewport(0)->getActualWidth()-2))
			||(y>(_window->getViewport(0)->getActualTop()+_window->getViewport(0)->getActualHeight()-2))){  
			CEGUI::MouseCursor::getSingleton().hide();
			showMouseCursor(true);
		}else {
			sys->injectMousePosition(x,y);
			CEGUI::MouseCursor::getSingleton().show();
			showMouseCursor(false);
		}

		return true;
	}

	bool UISystem::mousePressed( const OIS::MouseEvent &e, OIS::MouseButtonID id )
	{

		CEGUI::System* sys=CEGUI::System::getSingletonPtr();
		if(!sys){
			return true;
		}

		

		updateIMEWindow();


		sys->injectMouseButtonDown(MouseButtonConverter::toCEGUI(id));

		if(id==OIS::MB_Right){
			CEGUI::MouseCursor::getSingleton().hide();
			return true;
		}

		return true;
	}

	bool UISystem::mouseReleased( const OIS::MouseEvent &e, OIS::MouseButtonID id )
	{
		CEGUI::System* sys=CEGUI::System::getSingletonPtr();
		if(!sys){
			return true;
		}

		sys->injectMouseButtonUp(MouseButtonConverter::toCEGUI(id));

		if(id==OIS::MB_Right){
			CEGUI::MouseCursor::getSingleton().show();
			
			
			unsigned int width, height, depth;
			int left, top;
			_window->getMetrics( width, height, depth, left, top );

			OIS::Mouse* mouse=InputSystem::getSingleton().getMouse();
			//mouse->getMouseState().X.abs=width/2;
			
			//const OIS::MouseState &mouseState = mouse->getMouseState();
			//mouseState.X.abs  = width/2;
			//mouseState.Y.abs  = height/2;
			
			//const OIS::MouseState &state = mouse->getMouseState();
			//state.X.abs=width/2;
			//state.Y.abs=height/2;

			return true;
		}

		return true;
	}


	bool UISystem::keyPressed(const OIS::KeyEvent &e)
	{
		CEGUI::System* sys=CEGUI::System::getSingletonPtr();
		if(!sys){
			return true;
		}

		updateIMEWindow();


		if(e.key==OIS::KC_ESCAPE){
			//exit app?
			return true;
		}

		if(e.key==OIS::KC_BACK||e.key==OIS::KC_LEFT||e.key==OIS::KC_RIGHT){
			CEGUI::System::getSingleton().injectKeyDown(e.key);
			return true;
		}

		if(!IMECHS::getSingleton().isLock()){
			CEGUI::System::getSingleton().injectKeyDown(e.key);
		}

		IMECHS::getSingleton().injectChar(_window,(CEGUI::utf32)e.text);
		
		
		return true;
	}

	bool UISystem::keyReleased( const OIS::KeyEvent &e )
	{
		CEGUI::System* sys=CEGUI::System::getSingletonPtr();
		if(!sys){
			return true;
		}

		sys->injectKeyUp(e.key);
		return true;
	}


	const CEGUI::Vector2 UISystem::getCaretPos(const CEGUI::MultiLineEditbox* box)
	{
		CEGUI::Vector2 pos;
		size_t caretIndex=box->getCaratIndex();
		size_t lineNumber=box->getLineNumberFromIndex(caretIndex);
		CEGUI::Font *font=box->getFont();
		pos.d_y=(lineNumber+1)*font->getFontHeight();

		const CEGUI::MultiLineEditbox::LineList& lineList=box->getFormattedLines();
		size_t lineListSize=lineList.size();

		const CEGUI::MultiLineEditbox::LineInfo& lineInfo=lineList.at(lineNumber);
		CEGUI::String str=box->getText();

		size_t startIndex=lineInfo.d_startIdx;
		str=str.substr(startIndex,caretIndex-startIndex);
		pos.d_x=font->getTextExtent(str);


		CEGUI::Rect rect=box->getTextRenderArea();
		pos.d_x-=rect.d_left;
		pos.d_y-=rect.d_top;

		CEGUI::Vector2 screenPos=CEGUI::CoordConverter::windowToScreen(*box,pos);

		return screenPos;

	}

	const CEGUI::Vector2 UISystem::getCaretPos(const CEGUI::Editbox* box)
	{
		CEGUI::Vector2 pos;
		size_t caretIndex=box->getCaratIndex();
		CEGUI::Font *font=box->getFont();
		pos.d_y=font->getFontHeight();

		CEGUI::String str=box->getText();
		str=str.substr(0,caretIndex);
		pos.d_x=font->getTextExtent(str);

		CEGUI::Vector2 screenPos=CEGUI::CoordConverter::windowToScreen(*box,pos);

		return screenPos;

	}

	void UISystem::updateIMEWindow()
	{
		HKL hkl=GetKeyboardLayout(0);
		if(!ImmIsIME(hkl)){
			return;//just return if direct input
		}

		CEGUI::Window* window=CEGUI::System::getSingleton().getGUISheet()->getActiveChild();
		const CEGUI::String& type=window->getType();
	
		CEGUI::Vector2 pt;
		const std::string t=StringConverter::toStd(type);
		if(type=="GuiLook/Editbox"){
			CEGUI::Editbox * box = static_cast<CEGUI::Editbox*>(window);
			
			pt= getCaretPos(box);
		}else if(type == "TaharezLook/MultiLineEditbox" 
			|| type == "Vanilla/MultiLineEditbox"
			|| type == "WindowsLook/MultiLineEditbox"){

			CEGUI::MultiLineEditbox* box = static_cast<CEGUI::MultiLineEditbox*>(window);
			pt= getCaretPos(box);
		}

		setImmCompositionWindowPos(pt.d_x,pt.d_y);

	}

}
